package proj1.dao;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;

import proj1.constants.C.COMPARATOR;
import proj1.dao.Radiator.SIZE;
import proj1.oracle.OracleDB;
import proj1.util.Logger;

public class Model {
	private static Logger log = Logger.getLogger(Model.class);
	private static final String tablePrefix = "APL";
	
	private Make make;
	private String model;
	private Integer hashCode;
	private Integer year;
	private String description;
	private String litres;
	private String engineType;
	private String cubicInches;
	private Long rLink;
	
	public static Set<Model> getModels(Make make){
		OracleDB conn = OracleDB.getInstance();
		String query = "select * from " + tablePrefix + make.getTableId();
		Set<Model> result = new TreeSet<Model>(COMPARATOR.MODEL);
		
		// For each item in the results, create a new Model object and add it to the result set
		try {
			// Execute the query via the OracleDB connection
			ResultSet rs = conn.executeQuery(query);
			
			while(rs.next())
				result.add(
					new Model(
							make, 
							rs.getString("MODEL"),
							rs.getInt("YEAR"),
							rs.getString("DESCRIPTION"),
							rs.getString("LITRES"),
							rs.getString("ENGINE_TYPE"),
							rs.getString("CUBIC_INCHES"),
							rs.getLong("RLINK")
						)
				);
		} catch (SQLException e) {
			log.error("A SQL Exception occurred during Make fetch.", e);
		}
		return result;
	}
	
	public Model(Make make, String model, Integer year, String description, String litres, String engineType, String cubicInches, Long rLink){
		this.make = make;
		this.model = model;
		this.year = year;
		this.description = description;
		this.litres = litres;
		this.engineType = engineType;
		this.cubicInches = cubicInches;
		this.rLink = rLink;
	}
	
	public Map<Vendor,Set<Radiator>> getRadiators(SIZE size){
		OracleDB conn = OracleDB.getInstance();
		TreeMap<Vendor,Set<Radiator>> radiatorsByVendor = new TreeMap<Vendor,Set<Radiator>>(COMPARATOR.VENDOR);
		
		for(Vendor vendor : Vendor.getVendors()){
			// Build the query and insert results into the radiators set
			String query = "select rad.* from radcrx crx" 
						+ " join RDIM" + vendor.name() + " rad"
						+ " on crx." + vendor.name() + size.colNum + " = rad.p_number "
						+ " where crx.rlink = " + this.rLink;
			
			try {
				// Execute the query via the OracleDB connection
				Set<Radiator> radiators = Radiator.radiatorsFromResults(conn.executeQuery(query));
				
				// Only add to the result if any results were actually returned from the database
				if(!radiators.isEmpty())
					radiatorsByVendor.put(vendor, radiators);
				
			} catch (SQLException e) {
				log.error("A SQL Exception occurred during radiator by model fetch.", e);
			}
		}
		return radiatorsByVendor;
	}

	public String getModel() {
		return model;
	}
	
	public Integer getYear(){
		return year;	
	}
	
	public String getDescription(){
		return description;
	}
	
	public Long getRLink(){
		return rLink;
	}
	
	@Override
	public boolean equals(Object other){
		if(other == null)
			return false;
		
		if (!(other instanceof Model))
			return false;
	
		Model oModel = (Model) other;
		if(!make.equals(oModel.make))
			return false;
		
		if(!model.equals(oModel.model))
			return false;
		
		if(!year.equals(oModel.year))
			return false;
		
		if(!litres.equals(oModel.litres))
			return false;
		
		if(!description.equals(oModel.description))
			return false;
		
		if(!engineType.equals(oModel.engineType))
			return false;
		
		if(!cubicInches.equals(oModel.cubicInches))
			return false;
		
		if(!rLink.equals(oModel.rLink))
			return false;
		
		return true;
	}

	@Override
	public int hashCode(){
		synchronized(this){
			if(hashCode != null){
				hashCode = 17;
				hashCode = 37 * hashCode + (this.make != null ? this.make.hashCode() : 0);
				hashCode = 37 * hashCode + (this.model != null ? this.model.hashCode() : 0);
				hashCode = 37 * hashCode + (this.year != null ? this.year.hashCode() : 0);
				hashCode = 37 * hashCode + (this.litres != null ? this.litres.hashCode() : 0);
				hashCode = 37 * hashCode + (this.description != null ? this.description.hashCode() : 0);
				hashCode = 37 * hashCode + (this.engineType != null ? this.engineType.hashCode() : 0);
				hashCode = 37 * hashCode + (this.cubicInches != null ? this.cubicInches.hashCode() : 0);
				hashCode = 37 * hashCode + (this.rLink != null ? this.rLink.hashCode() : 0);
			}
		}
		return hashCode.intValue();
	}
	
	@Override
	public String toString(){
		return  engineType + " " + description + " " + cubicInches + "cc";
	}
}
